#include "include/gstplayer.h"
#include <gst/gst.h>
#include <stdlib.h>
#include <iostream>
#include <string.h>
#include <thread>
#include <unistd.h>
#include <vector>
#include <portaudio.h>

typedef short SAMPLE;

using namespace std;


GstPlayer::GstPlayer(int argc, char *argv[])
{
    init(argc,argv);

}

GstPlayer::~GstPlayer()
{

}

void GstPlayer::init(int argc, char *argv[])
{
    gst_init(&argc,&argv);
//    data.playbin = gst_element_factory_make("playbin","playbin");

    data.pipeline = gst_pipeline_new("playback");
    data.source = gst_element_factory_make("filesrc","source");
    data.decoder = gst_element_factory_make("mad","decoder");
    data.sink = gst_element_factory_make("alsasink","sink");

    if(!data.pipeline ||!data.source||!data.decoder||!data.sink){
	cout<<data.pipeline<<endl;
        g_printerr("element created error......\n");
        exit(1);
    }

    gst_bin_add_many(GST_BIN(data.pipeline), data.source, data.decoder, data.sink, NULL);
    if(gst_element_link_many(data.source,data.decoder,data.sink, NULL)!= TRUE)
    {
        g_printerr("element link error.....\n");
        exit(1);
    }
}

void GstPlayer::Control(const char *filepath)
{
    g_object_set(G_OBJECT(data.source), "location", filepath, NULL);

    GstStateChangeReturn ret = gst_element_set_state(data.pipeline,GST_STATE_PLAYING);
    if(ret == GST_STATE_CHANGE_FAILURE)
    {
        g_printerr("Unable to play......\n");
        gst_object_unref(data.pipeline);
        exit(1);
    }
}

void GstPlayer::start(const char *filepath)
{

    thread t1(&GstPlayer::_start,this,filepath,data);
    t1.detach();
//    _start(filepath,data);
}

void GstPlayer::hello(GstState state)
{
    sleep(3);
    GstStateChangeReturn ret = gst_element_set_state(data.playbin,state);
    if(ret == GST_STATE_CHANGE_FAILURE)
    {
        g_printerr("Unable to play......\n");
//        gst_object_unref(pipeline);
        exit(1);
    }
}


void GstPlayer::_start(const char *filepath,CustomData data)
{
//    GstMessage *msg;
    //gboolean terminate=FALSE;
    GstStateChangeReturn ret;

//    char uriPath[100] = "file://";
//    strcat(uriPath,filepath);

    cout<<"playing "<<filepath<<endl;
    g_object_set(G_OBJECT(data.source), "location", filepath, NULL);
//    g_object_set(data.playbin, "uri", uriPath, NULL);
    bus = gst_element_get_bus(data.pipeline);
//    msg = gst_bus_timed_pop_filtered(bus,GST_CLOCK_TIME_NONE,(GstMessageType)(GST_MESSAGE_ERROR|GST_MESSAGE_EOS));
    gst_bus_add_watch(bus,((GstBusFunc)handle_message),&data);

    /*Start Playing*/
    ret = gst_element_set_state(data.pipeline,GST_STATE_PLAYING);
    if(ret == GST_STATE_CHANGE_FAILURE)
    {
        g_printerr("Unable to play......\n");
        gst_object_unref(data.pipeline);
        exit(1);
    }

    data.main_loop = g_main_loop_new(NULL,FALSE);
    g_main_loop_run(data.main_loop);

    g_main_loop_unref(data.main_loop);
    gst_object_unref(bus);

//    gst_object_unref(data.pipeline);
//    gst_object_unref(data.source);
//    gst_object_unref(data.decoder);
//    gst_object_unref(data.sink);
}

gboolean GstPlayer::handle_message(GstBus *bus, GstMessage *msg,CustomData *data)
{
    GError *err;
    gchar *debug_info;

    switch(GST_MESSAGE_TYPE(msg)){
        case GST_MESSAGE_ERROR:
            gst_message_parse_error(msg,&err,&debug_info);
            g_printerr("Error received from element %s: %s\n",GST_OBJECT_NAME(msg->src),err->message);
            g_printerr("Debugging information: %s\n",debug_info ? debug_info: "none");
            g_clear_error(&err);
            g_free(debug_info);
            g_main_loop_quit(data->main_loop);
            break;

        case GST_MESSAGE_EOS:
            g_print("End Of Stream reached...\n");
            gst_element_set_state(data->pipeline,GST_STATE_READY);
            g_main_loop_quit(data->main_loop);
            break;

        case GST_MESSAGE_STATE_CHANGED:
            if(GST_MESSAGE_SRC(msg)==GST_OBJECT(data->pipeline))
            {
                GstState old_state,new_state,pending_state;
                gst_message_parse_state_changed(msg,&old_state,&new_state,&pending_state);
                g_print("pipeline state changed from %s to %s\n",
                        gst_element_state_get_name(old_state),gst_element_state_get_name(new_state));
                g_print("pending state: %s\n",gst_element_state_get_name(pending_state));
            }
         default:
            {

            }

    return TRUE;
    }
}



